﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace KrileUpdater
{
    public partial class UpdateForm : Form
    {
        public UpdateForm()
        {
            InitializeComponent();
        }

        private void Write(string txt)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(Write), txt);
            }
            else
            {
                detailBox.AppendText(txt);
                Application.DoEvents();
            }
        }

        private void WriteLine(string txt)
        {
            this.Write(txt + Environment.NewLine);
        }

        UpdateProcessor up = null;
        private void UpdateForm_Shown(object sender, EventArgs e)
        {
            var cmd = Environment.GetCommandLineArgs();
            if(cmd.Length < 2)
            {
#if DEBUG
                cmd = new[] { "", "0.00" };
#else
                MessageBox.Show("Information losted.", "Updater", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                Application.Exit();
                return;
#endif
            }
            double ver = double.Parse(cmd[1]);
            Write("Initializing...");
            up = new UpdateProcessor(Write);
            this.Text = "Krile Update " + up.UpdaterVersion;
            up.Destination = Application.StartupPath;
            up.SetCancellable += new Action<bool>(up_SetCancellable);
            WriteLine("done.");
            Write("Waiting for exit Krile...");
            int pid;
            if (cmd.Length >= 3 &&
                int.TryParse(cmd[2], out pid))
            {
                //プロセス終了を待つ
                Write("(waiting pid:" + pid.ToString() + ")...");
                try
                {
                    var p = Process.GetProcessById(pid);
                    if (ver == 0.760)
                        p.Kill();
                    for(int i = 0; i < 10 && !p.HasExited; i++)
                    {
                        p.WaitForExit(1000);
                        Write(".");
                    }
                    WriteLine("");

                    if (!p.HasExited)
                    {
                        //Krileがシャットダウンしない
                        WriteLine("<!>Krile maybe hang-upping! try to kill...");
                        p.Kill();
                        Write("Waiting for exit Krile again...");
                        for (int i = 0; i < 10; i++)
                        {
                            Write(".");
                            p.WaitForExit(100);
                        }
                        WriteLine("");
                        if(p.HasExited)
                            WriteLine("Krile process shut-downed.");
                        else
                        {
                            WriteLine("Krile can't kill.");
                            MessageBox.Show(
                                "Fatal: Updater couldn't stop Krile." + Environment.NewLine +
                                "Updater fail to update. Operation cancelled.",
                                "Updater error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                            Application.Exit();
                        }
                    }
                }
                catch
                {
                    Write("::pinfo get failed.");
                }
            }
            else
            {
                Write("(compatible wait mode)...");
                int gi = 0;
                while (true)
                {
                    gi++;
                    var ps = Process.GetProcesses();
                    Process tp = null;
                    foreach (var p in ps)
                    {
                        if (p.ProcessName == "krile")
                        {
                            tp = p;
                            if (tp.WaitForExit(100))
                                tp = null;
                            else
                                break;
                        }
                    }
                    if (tp == null)
                        break;
                    else
                    {
                        if (gi == 50)
                        {
                            WriteLine("Using enforce kill...");
                        }
                        if (gi >= 50)
                        {
                            tp.Kill();
                        }
                    }
                    Application.DoEvents();
                }
            }
            Action<double> act = new Action<double>(up.DoUpdate);
            act.BeginInvoke(ver, (iar) =>
            {
                ((Action<double>)iar.AsyncState).EndInvoke(iar);
                Write("Finalizing update.");
                for (int i = 0; i < 5; i++)
                {
                    Write(".");
                    for (int j = 0; j < 10; j++)
                        System.Threading.Thread.Sleep(10);
                }
                WriteLine("Automatic update has successfully completed!");
                WriteLine("Please start a few seconds for restarting Krile...");
                Application.Exit();
            }, act);
        }

        void up_SetCancellable(bool obj)
        {
            this.CancelBtn.Enabled = obj;
        }

        private void CancelBtn_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}
